﻿#include "cfilestorageimpl.h"
#include "json.hpp"
#include <algorithm>
#include <cstring>
#include <curl/curl.h>
#include <fstream>
#include <sstream>

using json = nlohmann::json;

// Base64编码表
const std::string base64_chars =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "abcdefghijklmnopqrstuvwxyz"
    "0123456789+/";

CFileStorageImpl::CFileStorageImpl()
{
    curl_global_init(CURL_GLOBAL_DEFAULT);
}

void CFileStorageImpl::setServiceAddress(const std::string &url)
{
    serviceAddress = url;
}

std::string CFileStorageImpl::getLastErrorText() const
{
    return lastErrorText;
}

// 回调函数用于接收HTTP响应
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, std::string *s)
{
    size_t newLength = size * nmemb;
    try
    {
        s->append((char *)contents, newLength);
    }
    catch (std::bad_alloc &e)
    {
        return 0;
    }
    return newLength;
}

bool CFileStorageImpl::sendChunk(const std::string &remotePath, uint64_t offset, const std::vector<uint8_t> &chunk)
{
    if (serviceAddress.empty())
    {
        lastErrorText = "未设置服务地址";
        return false;
    }

    CURL *curl = curl_easy_init();
    if (!curl)
    {
        lastErrorText = "curl初始化失败";
        return false;
    }

    // 构建JSON请求
    json req;
    req["path"] = remotePath;
    req["offset"] = offset;
    req["data"] = base64Encode(chunk);
    req["length"] = chunk.size();
    std::string postData = req.dump();

    std::string url = serviceAddress + "/write";
    std::string response_string;

    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_string);

    // 设置HTTP头部
    struct curl_slist *headers = nullptr;
    headers = curl_slist_append(headers, "Content-Type: application/json");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

    // 执行请求
    CURLcode res = curl_easy_perform(curl);
    if (res != CURLE_OK)
    {
        lastErrorText = "网络错误: " + std::string(curl_easy_strerror(res));
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        return false;
    }

    // 检查HTTP响应码
    long http_code = 0;
    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
    if (http_code != 200)
    {
        lastErrorText = "HTTP错误: " + std::to_string(http_code);
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        return false;
    }

    // 解析响应
    try
    {
        json response = json::parse(response_string);
        if (response["status"].get<int>() != 0)
        {
            lastErrorText = "服务器返回错误: " + response["statusText"].get<std::string>();
            curl_slist_free_all(headers);
            curl_easy_cleanup(curl);
            return false;
        }
    }
    catch (const std::exception &e)
    {
        lastErrorText = "解析服务器响应失败: " + std::string(e.what());
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        return false;
    }

    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);
    return true;
}

bool CFileStorageImpl::receiveChunk(const std::string &remotePath, uint64_t offset, std::vector<uint8_t> &chunk)
{
    if (serviceAddress.empty())
    {
        lastErrorText = "未设置服务地址";
        return false;
    }

    CURL *curl = curl_easy_init();
    if (!curl)
    {
        lastErrorText = "curl初始化失败";
        return false;
    }

    // 构建JSON请求
    json req;
    req["path"] = remotePath;
    req["offset"] = offset;
    req["length"] = CHUNK_SIZE;
    std::string postData = req.dump();

    std::string url = serviceAddress + "/read";
    std::string response_string;

    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_string);

    // 设置HTTP头部
    struct curl_slist *headers = nullptr;
    headers = curl_slist_append(headers, "Content-Type: application/json");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

    // 执行请求
    CURLcode res = curl_easy_perform(curl);
    if (res != CURLE_OK)
    {
        lastErrorText = "网络错误: " + std::string(curl_easy_strerror(res));
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        return false;
    }

    // 检查HTTP响应码
    long http_code = 0;
    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
    if (http_code != 200)
    {
        lastErrorText = "HTTP错误: " + std::to_string(http_code);
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        return false;
    }

    // 解析响应
    try
    {
        json response = json::parse(response_string);
        if (response["status"].get<int>() != 0)
        {
            lastErrorText = "服务器返回错误: " + response["statusText"].get<std::string>();
            curl_slist_free_all(headers);
            curl_easy_cleanup(curl);
            return false;
        }

        std::string base64Data = response["data"].get<std::string>();
        chunk = base64Decode(base64Data);
    }
    catch (const std::exception &e)
    {
        lastErrorText = "解析服务器响应失败: " + std::string(e.what());
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        return false;
    }

    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);
    return true;
}

bool CFileStorageImpl::pushFile(const std::string &localPath, const std::string &remotePath)
{
    std::ifstream file(localPath, std::ios::binary | std::ios::ate);
    if (!file.is_open())
    {
        lastErrorText = "无法打开本地文件: " + localPath;
        return false;
    }

    std::streamsize fileSize = file.tellg();
    file.seekg(0, std::ios::beg);

    uint64_t offset = 0;
    std::vector<uint8_t> chunk(CHUNK_SIZE);

    while (offset < static_cast<uint64_t>(fileSize))
    {
        size_t bytesToRead = static_cast<size_t>(std::min(static_cast<std::streamsize>(CHUNK_SIZE), fileSize - static_cast<std::streamsize>(offset)));

        if (!file.read(reinterpret_cast<char *>(chunk.data()), bytesToRead))
        {
            lastErrorText = "读取文件失败";
            file.close();
            return false;
        }

        chunk.resize(bytesToRead);
        if (!sendChunk(remotePath, offset, chunk))
        {
            file.close();
            return false;
        }

        offset += bytesToRead;
    }

    file.close();
    return true;
}

bool CFileStorageImpl::pullFile(const std::string &localPath, const std::string &remotePath)
{
    std::ofstream file(localPath, std::ios::binary);
    if (!file.is_open())
    {
        lastErrorText = "无法创建本地文件: " + localPath;
        return false;
    }

    uint64_t offset = 0;
    std::vector<uint8_t> chunk;

    while (true)
    {
        if (!receiveChunk(remotePath, offset, chunk))
        {
            file.close();
            return false;
        }

        if (chunk.empty())
        {
            break;
        }

        file.write(reinterpret_cast<const char *>(chunk.data()), chunk.size());
        if (!file)
        {
            lastErrorText = "写入文件失败";
            file.close();
            return false;
        }

        offset += chunk.size();

        if (chunk.size() < CHUNK_SIZE)
        {
            break;
        }
    }

    file.close();
    return true;
}

bool CFileStorageImpl::pushData(const std::vector<uint8_t> &localData, const std::string &remotePath)
{
    if (localData.empty())
    {
        lastErrorText = "数据为空，无法上传";
        return false;
    }

    uint64_t offset = 0;
    const size_t dataSize = localData.size();

    while (offset < dataSize)
    {
        size_t bytesToSend = std::min(CHUNK_SIZE, dataSize - offset);
        std::vector<uint8_t> chunk(localData.begin() + offset, localData.begin() + offset + bytesToSend);

        if (!sendChunk(remotePath, offset, chunk))
        {
            return false;
        }

        offset += bytesToSend;
    }

    return true;
}

bool CFileStorageImpl::pullData(std::vector<uint8_t> &localData, const std::string &remotePath)
{
    localData.clear();

    uint64_t offset = 0;
    std::vector<uint8_t> chunk;

    while (true)
    {
        if (!receiveChunk(remotePath, offset, chunk))
        {
            return false;
        }

        if (chunk.empty())
        {
            break;
        }

        localData.insert(localData.end(), chunk.begin(), chunk.end());
        offset += chunk.size();

        if (chunk.size() < CHUNK_SIZE)
        {
            break;
        }
    }

    return true;
}

// Base64编码实现
std::string CFileStorageImpl::base64Encode(const std::vector<uint8_t> &data)
{
    std::string result;
    int i = 0;
    int j = 0;
    uint8_t char_array_3[3];
    uint8_t char_array_4[4];

    for (size_t n = 0; n < data.size(); n++)
    {
        char_array_3[i++] = data[n];
        if (i == 3)
        {
            char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
            char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
            char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
            char_array_4[3] = char_array_3[2] & 0x3f;

            for (i = 0; (i < 4); i++)
                result += base64_chars[char_array_4[i]];
            i = 0;
        }
    }

    if (i > 0)
    {
        for (j = i; j < 3; j++)
            char_array_3[j] = '\0';

        char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
        char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
        char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
        char_array_4[3] = char_array_3[2] & 0x3f;

        for (j = 0; (j < i + 1); j++)
            result += base64_chars[char_array_4[j]];

        while ((i++ < 3))
            result += '=';
    }

    return result;
}

static inline bool is_base64(uint8_t c)
{
    return (isalnum(c) || (c == '+') || (c == '/'));
}

// Base64解码实现
std::vector<uint8_t> CFileStorageImpl::base64Decode(const std::string &encoded)
{
    size_t in_len = encoded.size();
    int i = 0;
    int j = 0;
    int in_ = 0;
    uint8_t char_array_4[4], char_array_3[3];
    std::vector<uint8_t> result;

    while (in_len-- && (encoded[in_] != '=') && is_base64(encoded[in_]))
    {
        char_array_4[i++] = encoded[in_];
        in_++;
        if (i == 4)
        {
            for (i = 0; i < 4; i++)
                char_array_4[i] = base64_chars.find(char_array_4[i]);

            char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
            char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
            char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

            for (i = 0; (i < 3); i++)
                result.push_back(char_array_3[i]);
            i = 0;
        }
    }

    if (i)
    {
        for (j = i; j < 4; j++)
            char_array_4[j] = 0;

        for (j = 0; j < 4; j++)
            char_array_4[j] = base64_chars.find(char_array_4[j]);

        char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
        char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
        char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

        for (j = 0; (j < i - 1); j++)
            result.push_back(char_array_3[j]);
    }

    return result;
}
